-- UIFateChain
-- Create by cheny3 Nov/24/2016
-- 命运的链

-- UIFateChain继承自Layer
UIFateChain = class("UIFateChain", function()
    return cc.Layer:create();
end);

-- 内部变量申明
local BASE_SCALE    = 0.52;   -- 基础缩放
local MAX_POS_NUM   = 5;      -- 屏幕上最多5个位置
local scoutBtnCount = 1;
local curCount = 1;

-- 5个位置相关配置
local posSetting = {
    [1] = {["scale"] = 0.75, ["flip"] = true,  ["position"] = cc.p(0, -35)},
    [2] = {["scale"] = 1.00, ["flip"] = true,  ["position"] = cc.p(-10, -40)},
    [3] = {["scale"] = 1.25, ["flip"] = true,  ["position"] = cc.p(-20, -60)},
    [4] = {["scale"] = 1.25, ["flip"] = false, ["position"] = cc.p(20, -30)},
    [5] = {["scale"] = 0.75, ["flip"] = false, ["position"] = cc.p(-20, 0)},
};

local textSetting = {
    [1] = {["nameLabelPos"] = cc.p(0,2), ["petLabelPos"] = cc.p(0,20),},
    [2] = {["nameLabelPos"] = cc.p(-25,5), ["petLabelPos"] = cc.p(-25,23),},
    [3] = {["nameLabelPos"] = cc.p(-25,-5), ["petLabelPos"] = cc.p(-25,13),},
    [4] = {["nameLabelPos"] = cc.p(20,30), ["petLabelPos"] = cc.p(20,48),},
    [5] = {["nameLabelPos"] = cc.p(-15,35), ["petLabelPos"] = cc.p(-15,53),},
};

function UIFateChain.create()
    return UIFateChain.new();
end

-- 构造函数
function UIFateChain:ctor()
    -- 初始化
    self:setName("UIFateChain");
    local node = cc.CSLoader:createNode("layout/fate_chain/FateChainMain.csb");
    self:addChild(node);
    self.node = node;

    -- 注册事件处理回调函数
    self:registerEventCallback();

    -- 注册点击事件
    self:registerTouchEvent();

    -- 重绘
    self:redraw();

    -- 适配
    self:resize();

    self.forbid = true;
    performWithDelay(self.node, function() self.forbid = false end, 0.8);
end

-- 适配
function UIFateChain:resize()
    local w = AlignM.frameSize.width;
    local h = AlignM.frameSize.height;

    local node = self.node;

    -- bg置于中间并缩放至合适大小
    AlignM.alignToCenter(node, "bg");

    -- CT居中并缩放至合适大小
    AlignM.alignToCenter(node, "CT");

    -- TOP顶部居中并缩放至合适大小
    AlignM.alignToTopCenter(node, "TOP");

    -- BT置于底部并缩放至合适大小
    AlignM.alignToBottomCenter(node, "BT");
end

-- 显示/隐藏底部BUTTON
function UIFateChain:showBottomBotton(visible)
    local BT = findChildByName(self.node, "BT");
    BT:setVisible(visible);
end

-- 获得焦点隐藏焦点
function UIFateChain:bottomFlyUp()
    local bottom = findChildByName(self.node, "BT");
    if bottom then
        bottom:setVisible(true);
        FormEffectM.btPopUpFromBottom(self);
    end
end

-- 重绘
function UIFateChain:redraw()
    -- 标题
    local titleLabel = findChildByName(self.node, "TOP/title_node/title_label");
    TextStyleM.setArtWordTitleStyle(titleLabel);
    titleLabel:setString(getLocStr("title_fate_stone"));

    -- 副标题
    local subTitle = findChildByName(self.node, "TOP/title_node/desc");
    local pointTitle = findChildByName(self.node, "TOP/title_node/desc2");
    subTitle:setVisible(false);
    pointTitle:setVisible(false);

    -- 英雄
    local bg = findChildByName(self.node, "bg");
    local heroPos = findChildByName(self.node, "bg/hero_pos");
    local petId = ME.user.dbase:query("active_pet");
    local pet = PetM.getMyPet(petId);
    local modelId = pet:getModelId();
    local heroImage = ccui.ImageView:create(getHeroLargeIconPath(PetM.queryModel(modelId, "large_icon")));
    heroImage:setScale(BASE_SCALE);
    heroImage:setPosition(cc.p(heroPos:getPosition()));
    bg.heroImage = heroImage;
    bg:addChild(heroImage);
    heroImage:setAnchorPoint(cc.p(0.5, 0));
    playSlightAnima(heroImage, BASE_SCALE, {["noChange"] = true});

    -- 蒙版
    local mask = findChildByName(self.node, "bg/mask");
    mask:setVisible(false);

    -- 探索节点
    local searchNode = findChildByName(self.node, "bg/search");
    local image = findChildByName(searchNode, "img");
    searchNode:setPosition(cc.p(50, 100));
    playBubbleAnima(searchNode, false, 0.9);
    image:loadTexture(getItemIconPath(ItemM.query(3066, "icon")));

    -- 检查提示
    self:checkTip();
end

-- 发起探索跳跃动作
function UIFateChain:startSearchEffect2()
    local bg = findChildByName(self.node, "bg");
    if not bg.heroImage then
        return;
    end

    -- 锁屏
    wait(2);
    bg.heroImage:stopAllActions();
    bg.heroImage:setScale(BASE_SCALE);

    -- 初始位置
    local heroPos = findChildByName(self.node, "bg/hero_pos");
    bg.heroImage:setPosition(cc.p(heroPos:getPosition()));

    -- 蒙版
    local mask = findChildByName(self.node, "bg/mask");
    mask:setVisible(true);

    -- 探索节点
    local searchNode = findChildByName(self.node, "bg/search");
    searchNode:setVisible(false);

    -- 跳跃
    local effectPos = findChildByName(self.node, "bg/effect_pos");
    local targetPos = cc.p(effectPos:getPosition());
    local function jump()
        fateChainSearchEffect(bg.heroImage, targetPos,
            function() playSlightAnima(bg.heroImage, BASE_SCALE, {["noChange"] = true}); end);
        -- 光效
        local function effect()
            local node = cc.Node:create();
            node:setPosition(cc.p(0, 125));
            effectPos:removeAllChildren();
            effectPos:addChild(node);
            playEffect(node, 1348);
        end
        performWithDelay(self.node, effect, 1.0);
    end
    -- 跳跃动作
    jump();
end

-- 发起探索烟尘动作
function UIFateChain:startSearchEffect()
    local bg = findChildByName(self.node, "bg");
    if not bg.heroImage then
        return;
    end

    -- 锁屏
    wait(2);
    bg.heroImage:stopAllActions();
    bg.heroImage:setScale(BASE_SCALE);

    -- 初始位置
    local heroPos = findChildByName(self.node, "bg/hero_pos");
    bg.heroImage:setPosition(cc.p(heroPos:getPosition()));

    -- 蒙版
    local mask = findChildByName(self.node, "bg/mask");
    mask:setVisible(true);

    -- 探索节点
    local searchNode = findChildByName(self.node, "bg/search");
    searchNode:setVisible(false);

    -- 跳跃
    local effectPos = findChildByName(self.node, "bg/effect_pos");
    local targetPos = cc.p(effectPos:getPositionX(), effectPos:getPositionY() + 18);
    local function disappearAndAppear()
        -- 消失
        local function disappear()
            local effectNode = cc.Node:create();
            effectNode:setPosition(cc.p(heroPos:getPosition()));
            bg:addChild(effectNode);
            setOpacity(bg.heroImage, 0);
            playEffect(effectNode, 1254, 0, 150);
            performWithDelay(self.node, function() bg:removeChild(effectNode) end, 0.5);
        end

        -- 出现
        local function appear()
            local effectNode = cc.Node:create();
            effectNode:setPosition(targetPos);
            bg:addChild(effectNode);
            bg.heroImage:setPosition(targetPos);
            performWithDelay(self.node, function() bg:removeChild(effectNode) end, 0.5);

            performWithDelay(self.node, function() setOpacity(bg.heroImage, 255); end, 0.05);
            performWithDelay(self.node, function() playEffect(effectNode, 1254, 0, 150); end, 0.01);

            playSlightAnima(bg.heroImage, BASE_SCALE, {["noChange"] = true});
        end

        disappear();
        performWithDelay(self.node, appear, 0.7);

        -- 搜索光效
        local function effect()
            local node = cc.Node:create();
            node:setPosition(cc.p(0, 125));
            effectPos:removeAllChildren();
            effectPos:addChild(node);
            playEffect(node, 1348);

            local subTitle = findChildByName(self.node, "TOP/title_node/desc");
            local pointTitle = findChildByName(self.node, "TOP/title_node/desc2");
            TextStyleM.setTextStyle(subTitle, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_BEIGE);
            subTitle:setVisible(true);
            TextStyleM.setTextStyle(pointTitle, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_BEIGE);
            pointTitle:setVisible(true);
            local str = getLocStr("search_tip1");
            subTitle:setString(str);
            subTitle.str = str;
            self:searchTextEffect();
        end
        performWithDelay(self.node, effect, 1.5);
    end
    -- 消失出现动作
    disappearAndAppear();
end

-- 注册事件处理回调函数
function UIFateChain:registerEventCallback()
    -- 注册获得焦点的回调
    EventMgr.register("UIFateChain", event.FOCUS_CHANGED, function(para)
        if para["get"] == "UIInvisibleForm" or para["lose"] == "UIInvisibleForm" then
            return;
        end

        -- 非初始化获得焦点，BOTTOM向上
        if para["get"] == "UIFateChain" then
            UIMgr:getCurrentScene().topMenu:show(TOPMENU_FRAME_FATE_CHAIN, TOPMENU_FRAME_FATE_LINK);
            if not self.isInit then
                self:bottomFlyUp();
            end
        elseif para["lose"] == "UIFateChain" then
            -- 失去焦点BOTTOM隐藏
            self:showBottomBotton(false);
        end

        if self.isInit then
            self.isInit = false;
        end
    end);

    -- 收到周围信息
    EventMgr.register("UIFateChain", event.NEARBY_INFO_ARRIVER, function(para)
        self:searchEventUpdate();
    end);

    -- 收到请求
    EventMgr.register("UIFateChain", event.RECEIVE_FATE_CHAIN, function(para)
        self:whenReceiveFate(para.info);
    end);

    -- 收到成功信息
    EventMgr.register("UIFateChain", event.FATE_CHAIN_SUCCESS, function(para)
        self:whenFateChainSuccess(para.info);
    end);

    -- 链接失败
    EventMgr.register("UIFateChain", event.FATE_CHAIN_FAIL, function(para)
        self:receiveFateFail(para.reason);
    end);

    -- 关注服务器状态更新事件
    EventMgr.register("UIFateChain", event.SERVER_STATUS_UPDATE, function(para)
        local data = para.data;
        if data["fate_chain_open"] ~= 1 then
            -- 命运之链禁止
            UIMgr.getCurrentScene():removeFormByName("UIShowTip");
            UIMgr.getCurrentScene():removeFormByName("UIFateChain");
            UIMgr.getCurrentScene():removeFormByName("UIFateChainEffect");
        end
    end);

    -- 领奖事件
    EventMgr.register("UIFateChain", event.FATE_CHAIN_TAKE_BONUS, function(para)
        self:checkTip();
    end);

    -- 界面析构后，需要清理下
    self:registerScriptHandler(function(eventType)
        if eventType == "exit" then
            cclog("UIFateChain 界面析构清理");
            EventMgr.removeAll("UIFateChain");

            -- 离开界面设置为失效
            FateChainM.endFateChain();
        elseif eventType == "enter" then

        end
    end);
end

-- 注册点击事件
function UIFateChain:registerTouchEvent()
    -- 注册返回按钮点击事件
    local btnBack = findChildByName(self.node, "BT/btn_back");
    local function onBackClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            -- 关闭当前界面
            AudioM.playFx("button_return");
            UIMgr.getCurrentScene():removeFormByName("UIFateChain");
        end
    end
    AddBackEventHandler(self, btnBack, onBackClick);
    TextStyleM.setTextStyle(btnBack, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnBack:setTitleText(getLocStr("btn_text_back"));

    -- 说明按钮
    local btnDesc = findChildByName(self.node, "BT/btn_desc");
    local function onDescClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            -- 音效
            AudioM.playFx("workshop_material");
            -- 描述比较多，这边拼一下
            local desc = "";
            for i = 1, 7 do
                desc = desc .. getLocStr("fate_desc" .. i);
            end
            desc = desc .. "\n\n";
            desc = desc .. "[blue]".. getLocStr("fate_detail_1");
            desc = desc .. getLocStr("fate_detail_2") .. "[-]";

            showActivityTip(getLocStr("title_fate_stone"), desc);
        end
    end
    btnDesc:addTouchEventListener(onDescClick);
    TextStyleM.setTextStyle(btnDesc, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnDesc:setTitleText(getLocStr("btn_text_help"));

    -- 列表
    local btnPot = findChildByName(self.node, "BT/btn_fate");
    local function onPotClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("workshop_material");

            require "game/ui/form/fate_chain/UIFateChainList"
            UIMgr.getCurrentScene():removeFormByName("UIFateChainList");
            local uiForm = UIFateChainList.create();
            UIMgr.getCurrentScene():addForm(uiForm);
        end
    end
    btnPot:addTouchEventListener(onPotClick);
    TextStyleM.setTextStyle(btnPot, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_BROWN_YELLOW, true);
    btnPot:setTitleText(getLocStr("btn_text_fate_chain"));

    -- 查询
    local searchNode = findChildByName(self.node, "bg/search");
    local function onSearchClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("workshop_material");
            -- 尝试查询
            self:searchEventUpdate();
            self:startFateChain();
        end
    end
    searchNode:addTouchEventListener(onSearchClick);
end

-- 玩家发起搜索
function UIFateChain:startFateChain()
    if self.tick or self.forbid then
        return;
    end
    self.tick = true;

    self:startSearchEffect();

    local function updateLocation()
        FateChainM.startFateChain();

        -- 每隔10s更新定位信息
        performWithDelay(self.node, updateLocation, 10);
    end

    -- 先发起定位
    updateLocation();

    local function delay()
        self.search = true;
        if FateChainM.getCurState() == FATE_CHAIN_STATE_FREE then
            -- 如果是空闲状态，则尝试搜索
            FateChainM.doSearch();
        end
        -- 每隔5s搜索一次
        performWithDelay(self.node, delay, 5);
    end

    -- 5s后开始搜索
    performWithDelay(self.node, delay, 5);
end

-- 列表排序
-- 如果是原来有的位置，就在原来的位置上
function UIFateChain:fixListSort(list)
    local ret = {};
    if not self.oriPosition then
        -- 初始化位置，是一个均为0的数组
        local initOri = {};
        for i = 1, MAX_POS_NUM do
            table.insert(initOri, 0);
        end
        self.oriPosition = initOri;
    end

    local new = {};
    for _, info in pairs(list) do
        local index = table.indexOf(self.oriPosition, info["rid"]);
        if index > 0 then
            -- 原来有位置，使用原来的
            ret[index] = info;
        else
            -- 新出现的
            info["newAppear"] = true;
            table.insert(new, info);
        end
    end

    -- 处理一下
    self.oriPosition = {};
    for index = 1, MAX_POS_NUM do
        if not ret[index] and #new > 0 then
            -- 新出现的，这个位置是空的，可以用
            ret[index] = new[1];
            table.remove(new, 1);
        end

        self.oriPosition[index] = (ret[index] or {})["rid"] or 0;
    end

    return ret;
end

-- 搜索状态更新
function UIFateChain:searchEventUpdate()
    if not self.search then
        -- 不是当次界面发起的请求
        return;
    end

    local list = table.deepcopy(FateChainM.getPlayerList()) or {};

    local subTitle = findChildByName(self.node, "TOP/title_node/desc");
    local pointTitle = findChildByName(self.node, "TOP/title_node/desc2");
    subTitle:setVisible(true);
    pointTitle:setVisible(true);

    TextStyleM.setTextStyle(subTitle, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_BEIGE);
    TextStyleM.setTextStyle(pointTitle, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_BEIGE);

    -- 收集一下rid
    local listRid = {};
    for _, info in pairs(list) do
        table.insert(listRid, info["rid"]);
    end

    if #list <= 0 then
        local str = getLocStr("search_tip1");
        subTitle:setString(str);
        subTitle.str = str;
        for i = 1, MAX_POS_NUM do
            local posNode = findChildByName(self.node, "bg/map/pos" .. i);
            posNode:removeAllChildren();
        end
    else
        if type(self.oriPosition) == "table" then
            for i = 1, MAX_POS_NUM do
                local posNode = findChildByName(self.node, "bg/map/pos" .. i);
                if type(self.oriPosition[i]) == "string"
                    and table.indexOf(listRid, self.oriPosition[i]) < 0 then
                    posNode:removeAllChildren();
                end
            end
        end

        local str = string.format(getLocStr("search_tip2"), #list);
        subTitle.str = str;
        local text2 = "";
        for i = 1, curCount do
            text2 = text2 .. ".";
        end
        subTitle:setString(str);
        pointTitle:setString(text2);
    end

    -- 特殊的排序方式
    list = self:fixListSort(list);

    for i = 1, MAX_POS_NUM do
        repeat
            local info = list[i];
            local posNode = findChildByName(self.node, "bg/map/pos" .. i);
            if not info then
                posNode:removeAllChildren();
                break;
            elseif not info["newAppear"] then
                break;
            end

            local icon = PetM.getDefaultLargeIcon(info["activity_pet"]);
            if tonumber(info["activity_costume"]) > 0 then
                -- 时装
                local modelId = EquipM.query(info["activity_costume"], "dbase")["pet_model_id"];
                icon = PetM.queryModel(modelId, "large_icon");
            end

            local image = ccui.ImageView:create(getHeroLargeIconPath(icon));
            posNode:addChild(image);

            local petLabel = ccui.Text:create();
            local nameLabel = ccui.Text:create();
            petLabel:setString(PetM.query(info["activity_pet"], "name"));
            nameLabel:setString(getNickName(info["name"]));
            -- TextStyleM.setTextStyle(petLabel, TextStyleM.TEXT_SIZE_TINY, TextStyleM.TEXT_COLOR_BRIGHT_YELLOW, false, getLocKerning() - 3 );
            petLabel:setFontSize(TextStyleM.TEXT_SIZE_MIDDLE2);
            petLabel:setScale(0.50);
            petLabel:setTextColor(TextStyleM.TEXT_COLOR_BRIGHT_YELLOW);
            TextStyleM.setShadowStyle(petLabel, cc.size(-0.3, -1.5), TextStyleM.TEXT_COLOR_BRIGHT_YELLOW);

            nameLabel:setFontSize(TextStyleM.TEXT_SIZE_MIDDLE2);
            nameLabel:setScale(0.50);
            nameLabel:setTextColor(TextStyleM.TEXT_COLOR_BEIGE);
            TextStyleM.setShadowStyle(nameLabel, cc.size(-0.3, -1.5), TextStyleM.TEXT_COLOR_BEIGE);
            posNode:addChild(petLabel);
            posNode:addChild(nameLabel);
            petLabel:setPosition(textSetting[i]["petLabelPos"]);
            nameLabel:setPosition(textSetting[i]["nameLabelPos"]);

            local settingInfo = posSetting[i];
            image:setScale(settingInfo["scale"] * BASE_SCALE);
            image:setFlippedX(settingInfo["flip"]);
            image:setPosition(settingInfo["position"]);

            -- 因为大图太大了，建个小图吸收点击事件
            local clickImage = ccui.ImageView:create(getHeroLargeIconPath(icon));
            clickImage:setPosition(settingInfo["position"]);
            clickImage:setScale(settingInfo["scale"] * BASE_SCALE * 0.6);
            posNode:addChild(clickImage);
            clickImage:setOpacity(0);

            if info["newAppear"] then
                -- 新出现的
                self:appearEffect(image, settingInfo);
            end

            self:registerInfoClick(clickImage, info);
        until true
    end
end

-- 弹出效果
function UIFateChain:appearEffect(node, settingInfo)
    node.oriScale = node:getScaleY();
    node:stopAllActions();

    node:setScale(0);
    local scaleUp = cc.ScaleTo:create(0.3, node.oriScale * 1.2);
    local scaleDown = cc.ScaleTo:create(0.1, node.oriScale);
    local scaleUp2 = cc.ScaleTo:create(0.1, node.oriScale * 1.1);
    local scaleDown2 = cc.ScaleTo:create(0.1, node.oriScale);
    node:runAction(cc.Sequence:create(scaleUp, scaleDown, scaleUp2, scaleDown2));

    performWithDelay(node, function() playSlightAnima(node, settingInfo["scale"] * BASE_SCALE); end, 1.0);
end

-- 注册点击事件
function UIFateChain:registerInfoClick(node, info)
    -- 查询
    node:setTouchEnabled(true);
    local function onClick(sender, eventType)
        if eventType == ccui.TouchEventType.ended then
            AudioM.playFx("workshop_material");
            -- 打开信息界面
            require "game/ui/form/fate_chain/UIFateChainUser"
            UIMgr.getCurrentScene():removeFormByName("UIFateChainUser");
            local uiForm = UIFateChainUser.create("request", info);
            UIMgr.getCurrentScene():addForm(uiForm);
        end
    end
    node:addTouchEventListener(onClick);
end

-- 收到请求
function UIFateChain:whenReceiveFate(info)
    -- 打开信息界面
    require "game/ui/form/fate_chain/UIFateChainUser"
    UIMgr.getCurrentScene():removeFormByName("UIFateChainUser");
    local uiForm = UIFateChainUser.create("answer", info);
    UIMgr.getCurrentScene():addForm(uiForm);
end

-- 收到请求失败
function UIFateChain:receiveFateFail(reason)
    -- 关闭界面
    UIMgr.getCurrentScene():removeFormByName("UIFateChainUser");

    -- 提示
    if reason == "target_busy" then
        -- 对方繁忙
        alert(getLocStr("fate_target_busy_tip"));
    elseif reason == "target_invaild" then
        -- 目标失效
        alert(getLocStr("fate_target_invalid_tip"));
    elseif reason == "target_refuse" then
        -- 对方拒绝
        alert(getLocStr("fate_target_refuse"));
    elseif reason == "target_cancel" then
        -- 发起方取消
        alert(getLocStr("fate_target_cancel"));
    end
end

-- 链接成功
function UIFateChain:whenFateChainSuccess(info)
    UIMgr.getCurrentScene():removeFormByName("UIFateChainUser");

    local petId = info["request_pet"];
    if info["request_rid"] == ME.user.rid then
        -- 自己发起的，显示对方的
        petId = info["answer_pet"];
    end

    local function showBonus()
        local msg = string.format(getLocStr("fate_chain_bonus_extra_desc"), PetM.query(petId, "name"));
        showBonusNotifyForm(getLocStr("achive_award"), info["bonus"],
            nil, nil, nil, nil, nil, nil, {["extraMsg"] = msg});
    end

    -- 不管是不是指定组合/都显示
    if true or tonumber(info["show_id"]) > 0 then
        require "game/ui/form/fate_chain/UIFateChainEffect"
        UIMgr.getCurrentScene():removeFormByName("UIFateChainEffect");
        local uiForm = UIFateChainEffect.create(info, showBonus);
        UIMgr.getCurrentScene():addForm(uiForm);
    else
        showBonus();
    end

    self:checkTip();
end

-- 检查
function UIFateChain:checkTip()
    local btnPot = findChildByName(self.node, "BT/btn_fate");
    local hint = findChildByName(btnPot, "hint");
    if FateChainM.hasBonusToTake() then
        hint:setVisible(true);
        checkBlueBubbleStatus(hint, true);
    else
        hint:setVisible(false);
    end
end

-- 搜索中...
function UIFateChain:searchTextEffect()
    local subTitle = findChildByName(self.node, "TOP/title_node/desc");
    local pointTitle = findChildByName(self.node, "TOP/title_node/desc2");

    if subTitle.isPlayingEffect then
        return;
    end

    local function tick()
        subTitle.isPlayingEffect = true;

        -- 原文本
        local str = subTitle.str;

        -- 正在探索
        local text2 = "";
        for i = 1, scoutBtnCount do
            text2 = text2 .. ".";
        end
        curCount = scoutBtnCount;
        scoutBtnCount = math.ceil(scoutBtnCount % 3 + 1)
        TextStyleM.setTextStyle(subTitle, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_BEIGE);
        TextStyleM.setTextStyle(pointTitle, TextStyleM.TEXT_SIZE_MINI, TextStyleM.TEXT_COLOR_BEIGE);
        subTitle:setString(str);

        local width = subTitle:getContentSize().width;
        pointTitle:setString(text2);
        pointTitle:setPosition(cc.p(width / 2 + 5, -57));
        pointTitle:getVirtualRenderer():setHorizontalAlignment(cc.TEXT_ALIGNMENT_LEFT);
        performWithDelay(self.node, tick, 0.5);
    end

    tick();
end